#include <windows.h>
#include <process.h>

#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
#include <ctime>

#include <stdio.h>
#include <DbgHelp.h>
#pragma comment (lib, "dbghelp.lib")

 #include "Game.h"

using std::cout;
using std::ifstream;
using std::string;
using std::istringstream;

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

LPCSTR applicationName = "DX11 2D";
HINSTANCE hInstance;
HWND hwnd;


LONG WINAPI CatchAll(_EXCEPTION_POINTERS *pExceptionInfo);
/*
Handle OS/System messages
*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
	switch(umessage)
	{
	case WM_CREATE: 
		{

		}
		break;

	case WM_INPUT:
		{

		}
		break;

	case WM_ACTIVATE:
		{
			//	gaining focus
			if (LOWORD(wparam) != WA_INACTIVE)
			{

			}
			else // losing focus
			{
				ClipCursor(NULL);
			}
		}
		break;

	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}
		break;

	case WM_CLOSE:
		{
			PostQuitMessage(0);		
			return 0;
		}
		break;

	default:
		{
			return DefWindowProc(hwnd, umessage, wparam, lparam);
		}
		break;
	}
	return 1;
}

/*
We want to initialize all application specific data here
*/
void InitializeApplication()
{
	srand((unsigned int)time(0));
}

void InitializeWindow()
{
	WNDCLASSEX wc;
	int posX, posY, windowWidth, windowHeight;

	DWORD dwWindowStyleFlags = WS_VISIBLE;

	dwWindowStyleFlags |= WS_CAPTION | WS_SYSMENU;

	hInstance = GetModuleHandle(NULL);

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon		 = LoadIcon(hInstance, IDI_WINLOGO);
	wc.hIconSm       = wc.hIcon;
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = applicationName;
	wc.cbSize        = sizeof(WNDCLASSEX);

	RegisterClassEx(&wc);

		dwWindowStyleFlags |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

		posX = (GetSystemMetrics(SM_CXSCREEN) - SCREEN_WIDTH)  / 2;
		posY = (GetSystemMetrics(SM_CYSCREEN) - SCREEN_HEIGHT) / 2;

		RECT rWindow;
		rWindow.left	= 0;
		rWindow.top		= 0;
		rWindow.right	= SCREEN_WIDTH;
		rWindow.bottom	= SCREEN_HEIGHT;

		AdjustWindowRectEx(&rWindow, dwWindowStyleFlags, FALSE, WS_EX_APPWINDOW);

		windowWidth		= rWindow.right - rWindow.left;
		windowHeight	= rWindow.bottom - rWindow.top;

	hwnd = CreateWindowEx(WS_EX_APPWINDOW, applicationName, applicationName, dwWindowStyleFlags,
		posX, posY, windowWidth, windowHeight, NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, SW_SHOW);
	SetForegroundWindow(hwnd);
	SetFocus(hwnd);
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{

	SetUnhandledExceptionFilter(CatchAll);

	MSG		msg;

	if ( hPrevInstance ) {
		return -1;
	}

	InitializeApplication();

	InitializeWindow();

	bool result = Game::Initialize(hInstance, hwnd, false, false, SCREEN_WIDTH, SCREEN_HEIGHT);

	if(!result)
	{
		return -1;
	}

	//VideoSettingsMenu::GetInstance()->SetBrightness(NULL, brightness);
	//VideoSettingsMenu::GetInstance()->SetGamma(gameGamma);

	ZeroMemory(&msg, sizeof(MSG));

	while(Game::isRunning)
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			if(msg.message == WM_QUIT)
			{
				Game::isRunning = false;
			}
			if(msg.message == WM_SIZE)
			{
				int width = (msg.lParam & 255);
				int height = (msg.lParam & 65280);
			}
		}
		else
		{
			Game::Run();
		}		
	}

	Game::Exit();

	ShowCursor(true);

	return 0;
}

int main()
{
	int msg = WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOWDEFAULT);

	return 0;
}

LONG WINAPI CatchAll(_EXCEPTION_POINTERS *pExceptionInfo)
{
	int index = 0;
	LPCTSTR filename = "dumpfile.mdmp";
	HANDLE hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL );

	char *report = NULL;
	if (hFile!=INVALID_HANDLE_VALUE)
	{
		_MINIDUMP_EXCEPTION_INFORMATION ExInfo;

		ExInfo.ThreadId = ::GetCurrentThreadId();
		ExInfo.ExceptionPointers = pExceptionInfo;
		ExInfo.ClientPointers = NULL;
		MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL );
		report = new char[1024];
		sprintf_s(report, 1024, "Look in dump file: dumpfile.mdmp\nThe error was:\n\n%d\n%s", ExInfo.ExceptionPointers->ExceptionRecord->ExceptionCode, ExInfo.ExceptionPointers->ExceptionRecord->ExceptionRecord->ExceptionInformation);
		MessageBox(NULL, report, "AHHH BREAK!",MB_OK);
		CloseHandle(hFile);
		delete[] report;
	}

	return 0;

}